package de.westranger.forex.trading.genetic.allel.fitness;

import java.util.LinkedList;
import java.util.List;

import de.westranger.forex.trading.genetic.allel.Node;
import de.westranger.forex.trading.genetic.allel.operator.CompareOperator;
import de.westranger.forex.trading.genetic.allel.operator.EvaluateTerminal;
import de.westranger.forex.trading.genetic.allel.operator.LogicalOperator;
import de.westranger.forex.trading.genetic.allel.operator.Util;

@Deprecated
public final class TreeSimplifier {
	private static final int IS_LOGICAL_OPERATOR = 1;
	private static final int IS_COMPARE_OPERATOR = 2;
	private static final int IS_EVALUATE_TERMINAL = 3;
	private static final int IS_TERMINAL = 4;
	
	private static final int SHIFT = 6;
	
	public void simplify(final Node node){
		final List<Node> queryNodes = new LinkedList<Node>();
		final List<Node> opt = new LinkedList<Node>();
		final List<Long> queryId = new LinkedList<Long>();
		
//		System.out.println("----");
		for(Node n:Util.getQueryNodes(node, Util.QUERY_OPERATORS)){
			if(checkIfLeaf(n)){
				queryNodes.add(n);
				queryId.add(getNodeIdentifier(n));
//				System.out.println(this.print(n) + "\t" +getNodeIdentifier(n));				
			}
		}
		
		// now we merge duplicate Nodes
		while(!queryNodes.isEmpty()){
			//System.out.println("----");
			for(int i=queryNodes.size()-1;i>0;i--){
				//System.out.print("compare: " + queryId.get(0) +" "+ queryId.get(i));
				if(queryId.get(0).compareTo(queryId.get(i)) == 0){
					//System.out.println("  replaced");
					this.replace(queryNodes.get(i),queryNodes.get(0));
					queryNodes.remove(i);
					queryId.remove(i);
				}//else{
					//System.out.println();
				//}
			}
			opt.add(queryNodes.get(0));
			queryNodes.remove(0);
			queryId.remove(0);
		}
		
		System.out.println("-----");

//		for(Node n:Util.getQueryNodes(node, Util.QUERY_OPERATORS)){
//			if(checkIfLeaf(n) && !queryNodes.contains(n)){
//				queryNodes.add(n);
//				System.out.println(this.print(n.getRoot()) + "\t" +getNodeIdentifier(n.getRoot()));				
//			}
//		}
		
		for(Node n:Util.getQueryNodes(node, Util.QUERY_OPERATORS)){
			if(!checkIfLeaf(n)){
				queryNodes.add(n);
				System.out.println(this.print(n) + "\t" +getNodeIdentifier(n) + "\t" + checkIfLeaf(n.getLeftChild())+ "\t" + checkIfLeaf(n.getRightChild()));				
			}
		}

		
//		System.out.println("----- opt");
//		for(Node n:opt){
//			System.out.println(this.print(n) + "\t" +getNodeIdentifier(n));
//		}
		// now can start merging parent nodes if they are equal
	}
	
	private void replace(final Node original,final Node replacement){
		final Node root = original.getRoot();
		original.setRoot(null);
		if(root.getLeftChild().equals(original)){
			root.setLeftChild(replacement);
		}else{// if(root.getRightChild().equals(original)){
			root.setRightChild(replacement);
		}//else{
//			try {
//				throw new Exception("da stimtm was nicht");
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
	}
	
	private boolean checkIfLeaf(final Node node){
		//System.out.println(getNodeAkro(node) + " "+ getNodeAkro(node.getRightChild()) + " " + getNodeAkro(node.getLeftChild()));
		if(getNodeAkro(node) == IS_COMPARE_OPERATOR && getNodeAkro(node.getRightChild()) == IS_TERMINAL && getNodeAkro(node.getLeftChild()) == IS_TERMINAL){
			return true;
		}else if(getNodeAkro(node) == IS_LOGICAL_OPERATOR && getNodeAkro(node.getRightChild()) == IS_EVALUATE_TERMINAL && getNodeAkro(node.getLeftChild()) == IS_EVALUATE_TERMINAL){
			return true;
		}else{
			return false;
		}
	}
	
	
	@Deprecated
	private String print(final Node node) {
		return node.getClass().getSimpleName() + ":\t" + node.getValue() + "("
				+ getNodeAkro(node) + ")" + node.getRightChild().getValue()
				+ "(" + getNodeAkro(node.getRightChild()) + ")"
				+ node.getLeftChild().getValue() + "("
				+ getNodeAkro(node.getLeftChild()) + ")";
	}
	
	private int getNodeAkro(final Node node){
		if(node instanceof LogicalOperator){
			return IS_LOGICAL_OPERATOR;
		}else if(node instanceof CompareOperator){
			return IS_COMPARE_OPERATOR;
		}else if(node instanceof EvaluateTerminal){
			return IS_EVALUATE_TERMINAL;
		}else { // terminal
			return IS_TERMINAL;
		}
	}
	
	private long getNodeIdentifier(final Node node){
		long result = node.getValue();
		result = result << SHIFT;
		result += getNodeAkro(node); 
		result = result << SHIFT;
		result += node.getRightChild().getValue();
		result = result << SHIFT;
		result += getNodeAkro(node.getRightChild());
		result = result << SHIFT;
		result += node.getLeftChild().getValue();
		result = result << SHIFT;
		result += getNodeAkro(node.getLeftChild());
		result = result << SHIFT;

		return result;
	}
	
}
